#!/usr/bin/python2.7

from MainWindow import *
import gtk
import threading
import GraphicalGraph
from Graph import *
from Vector2 import *
import time
import re

from xml.dom.minidom import parse


class BuildTool:
    def __init__(self):
        
        self.engine = BuildEngine()
        self.mainWindow = MainWindow(self.engine)

        self.mainWindow.show_all()

        
        
class BuildEngine:

    def __init__(self):
        self.graph = GraphicalGraph.GraphicalGraph()
        self.global_variables = {}
        self.threads = []
        self.currentProjectFilename = ""
    
    def setGlobalVariables(self, variables):
        self.global_variables = variables
    def getGlobalVariables(self):
        return self.global_variables
    
    def stop(self):
        for t in self.threads:
            t.stop()
        
    def getGlobalVariable(self, name):
        return self.global_variables[name]
    
    def newProject(self):
        self.stop() # stops the threads
        self.global_variables = {}
        self.threads = []
        self.currentProjectFilename = ""
        self.graph = GraphicalGraph.GraphicalGraph()
      
    def loadProject(self, filename):
        self.currentProjectFilename = filename
        doc = parse(filename)
        graphElement = doc.getElementsByTagName("graph")[0]
        globalElement = doc.getElementsByTagName("global")[0]
        variablesElement = globalElement.getElementsByTagName("variable")
        self.graph = GraphicalGraph.GraphicalGraph()
        self.graph.fromXml(graphElement.toxml())
        
        self.global_variables = {}
        for var in variablesElement:
            name = var.getAttribute("name")
            value = var.getAttribute("value")
            self.global_variables[name] = value

    def saveProject(self, filename):
        f = open(filename, "w")
        f.write("<project>\n")
        f.write(" <global>\n")
        for name, value in self.global_variables.items():
            f.write("<variable name=\""+name+"\" value=\"" + value + "\" />")
        f.write(" </global>\n")
        f.write(" <graph>\n")
        f.write(self.graph.toXml(2))
        f.write(" </graph>\n")
        f.write(" </project>\n")
        f.close()
            
   

    def importGraph(self, filename):
        """ Imports a new graph from a xml file """
        
        dom = xml.dom.minidom.parse(filename)
        graph = GraphicalGraph.GraphicalGraph()
        
        nodes = dom.getElementsByTagName("node")
        for node in nodes:
            project_filepath = node.getElementsByTagName("project")[0].firstChild.nodeValue
            project = MSProject(project_filepath)
            new_node = DependencyNode(project.name)
            new_node.setProject(project)
            graph.index = int(node.getAttribute("index"))
            graph.addNode(new_node)
        print len(nodes), "imported nodes"
            
        children = dom.getElementsByTagName("child")
        for child in children:
            parent_index = int(child.getAttribute("parent"))
            child_index = int(child.getAttribute("child"))
            try:
                parent_node = graph.getNodeFromIndex(parent_index)
                child_node = graph.getNodeFromIndex(child_index)
                graph.addEdge(parent_node, child_node)
            except:
                print "KeyError: (parent, child) = ("+str(parent_index) + "," + str(child_index)+")"
        self.graph = graph
    
    
        
    def execute(self, graph, dependency, textview=None):
        try:
            
            chain = queueDependenciesRec(graph, dependency)
            thread = ExecutorThread(chain, textview, self.global_variables)
            self.threads.append(thread)
            thread.start()
        except RuntimeError as e:
            addLineInTextview(textview, "There is a cycle in the graph... Oooops")
        
     
     
class ExecutorThread(threading.Thread):
    def __init__(self, chain, txtview, variables):
        super(ExecutorThread, self).__init__()
        self.chain = chain
        self.txtview = txtview
        self.variables = variables
        self.quit = False

    def run(self):
        mutex = threading.Lock()
        chainlist = "\n".join([dep.name for dep in self.chain])
        addLineInTextview(self.txtview, "===== Execution launched =====\n" + chainlist)
        
        for dep in self.chain:
            for command in dep.commands:
                determinedCommand = replaceCommandVariables(command, self.variables)
                addLineInTextview(self.txtview, "=== Dependency:"+ dep.name + ", command: \"" + determinedCommand + "\"")
                args = determinedCommand #.split(" ");
                p = subprocess.Popen(args, stdout=subprocess.PIPE)

                while not self.quit:
                    line = p.stdout.readline()
                    if not line: break
                    line = line.strip()
                    #print line
                    mutex1 = threading.Lock()
                    
                    mutex1.acquire()
                    gtk.threads_enter()
                    gobject.idle_add(addLineInTextview, self.txtview, line, mutex1, mutex)
                    gtk.threads_leave()
                    mutex1.acquire()
                    
                
                p.wait()
                if p.returncode <> 0:
                    addLineInTextview(self.txtview, "An error occurred with the command: "+ determinedCommand)
                    return
        addLineInTextview(self.txtview, "===== Execution successfully terminated =====")
        self.done = True
    
    def stop(self):
        self.quit = True
        
def replaceCommandVariables(command, variables):
    result = command
    for name, value in variables.items():
        result = re.sub("\$\("+name+"\)", value, result)
    return result  

def addLineInTextview(txtview, line, mutex=None, mutex2=None):
    #
    if not mutex2 is None:
        mutex2.acquire()
    txtbuffer = txtview.get_buffer()
    if not txtbuffer is None:
        #print line into buffer
        line_count = txtbuffer.get_line_count()
        if line_count > 100:
            last_line_iter = txtbuffer.get_bounds()[0]
            txtbuffer.delete(last_line_iter, last_line_iter)
        iter = txtbuffer.get_bounds()[1]
        #txtbuffer.insert(iter, line + "\n")
        print line
        #adj = txtview.get_vadjustment()
        #adj.set_value( adj.upper - adj.page_size )
    if not mutex is None:
        mutex.release()
    if not mutex2 is None:
        mutex2.release()
    #gtk.threads_leave()
        
def queueDependenciesRec(graph, dependency):
    # if no children
    if len(graph.children(dependency)) == 0:
        return [dependency]
    else:
        children = graph.children(dependency)
        chain = []
        for child in children:
            chain = chain + queueDependenciesRec(graph, child)
        chain.append(dependency)
        chain2 = []
        for el in chain:
            if not el in chain2:
                chain2.append(el)
        return chain2